package com.chianghao.qyt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chianghao.qyt.common.entity.BaseTenant;
import com.chianghao.qyt.common.entity.BaseTenantAccount;
import com.chianghao.qyt.exception.GetSeqLockException;
import com.chianghao.qyt.mapper.BaseTenantAccountMapper;
import com.chianghao.qyt.mapper.BaseTenantMapper;
import com.chianghao.qyt.mapper.SysOperationSequenceMapper;
import com.chianghao.qyt.service.TenantService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class TenantServiceImpl implements TenantService {

    @Resource
    BaseTenantAccountMapper baseTenantAccountMapper;

    @Resource
    BaseTenantMapper baseTenantMapper;

    @Resource
    SysOperationSequenceMapper sysOperationSequenceMapper;

    @Resource
    PasswordEncoder passwordEncoder;


    Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 获取随机字符
     * @param length 长度
     * @return 然会随机数
     */
    private String generateRandomAlphaNumeric(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            int randomLimitedInt = 48 + random.nextInt(123 - 48 + 1);
            char randomChar = (char) randomLimitedInt;
            if (randomLimitedInt < 58 || randomLimitedInt > 64) {
                sb.append(randomChar);
            }
        }
        return sb.toString();
    }



    @Override
    public IPage<BaseTenant> page(Integer pageIndex, Integer pageSize, String code, String name) {
        LambdaQueryWrapper<BaseTenant> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.isNotEmpty(code),BaseTenant::getTenantCode,code);
        wrapper.like(StringUtils.isNotEmpty(name),BaseTenant::getTenantName,name);
        return baseTenantMapper.selectPage(new Page<>(pageIndex,pageSize),wrapper);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void add(String name,String mobilePhone, String remark) {
        // 创建商户
        Long index= null;
        try{
            index = sysOperationSequenceMapper.getLock("tenant.code");
        } catch (Throwable e){
            log.error("获取锁异常",e);
            if(e instanceof SQLException){
                throw new GetSeqLockException();
            }else{
                throw e;
            }
        }

        String code = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String tenantCode = code+(index+1);
        BaseTenant baseTenant = new BaseTenant();
        baseTenant.setTenantCode(tenantCode);
        baseTenant.setTenantName(name);
        baseTenant.setState(true);
        baseTenant.setCreateTime(LocalDateTime.now());
        baseTenant.setMobilePhone(mobilePhone);
        baseTenant.setRemark(remark);
        this.baseTenantMapper.insert(baseTenant);

        // 创建商户的默认账号
        BaseTenantAccount account = new BaseTenantAccount();
        account.setTenantCode(tenantCode);
        account.setTenantId(baseTenant.getId());
        account.setAccount("admin");
        String password  = generateRandomAlphaNumeric(8);
        account.setPassword(passwordEncoder.encode(password));
        account.setDefaultAccount(true);
        this.baseTenantAccountMapper.insert(account);
        // 发送密码给开通的用户
        log.info("商户:{}开通信息为[编号:{}],[账号:{}],[密码:{}]",name,tenantCode,"admin",password);
        sysOperationSequenceMapper.upload("tenant.code",1);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void modify(Long id, String name, String mobilePhone,String remark) {
        if(StringUtils.isEmpty(name) &&
                StringUtils.isEmpty(mobilePhone) &&
                StringUtils.isEmpty(remark)
        ){
            return;
        }
        if(id==null){
            return;
        }
        new LambdaUpdateChainWrapper<BaseTenant>(this.baseTenantMapper)
                .set(StringUtils.isNotEmpty(name),BaseTenant::getTenantName,name)
                .set(StringUtils.isNotEmpty(mobilePhone),BaseTenant::getMobilePhone,mobilePhone)
                .set(StringUtils.isNotEmpty(remark),BaseTenant::getRemark,remark)
                .eq(BaseTenant::getId,id)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void setState(Long tenantId, Boolean state) {
        if(state==null&&tenantId==null){
            return;
        }
        new LambdaUpdateChainWrapper<BaseTenant>(this.baseTenantMapper)
                .set(BaseTenant::getState,state)
                .eq(BaseTenant::getId,tenantId)
                .update();
    }

    @Override
    public Map<Long, BaseTenantAccount> queryTenantDefaultAccountMap(Set<Long> tenantIds) {
        if(tenantIds==null || tenantIds.isEmpty()){
            return Map.of();
        }
        List<BaseTenantAccount> baseTenantAccounts = baseTenantAccountMapper.selectList(
                new QueryWrapper<BaseTenantAccount>().lambda()
                        .in(BaseTenantAccount::getTenantId,tenantIds)
                        .eq(BaseTenantAccount::getDefaultAccount,true)
        );
        return baseTenantAccounts.stream().collect(Collectors.toMap(BaseTenantAccount::getTenantId,a->a,(a,b)->b));
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void resetAccountPassword(Long tenantAccountId, String password) {
        if(StringUtils.isEmpty(password)){
            return;
        }
        new LambdaUpdateChainWrapper<BaseTenantAccount>(this.baseTenantAccountMapper)
                .eq(BaseTenantAccount::getId,tenantAccountId)
                .set(BaseTenantAccount::getPassword,passwordEncoder.encode(password))
                .update();
    }
}
